001 /*
002 * Copyright 2006 Stephen McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package net.dpml.http;
017
018 import java.net.URI;
019 import java.net.URL;
020 import java.util.ArrayList;
021
022 import net.dpml.logging.Logger;
023
024 import net.dpml.metro.PartsManager;
025 import net.dpml.metro.ComponentHandler;
026 import net.dpml.component.Provider;
027
028 import org.mortbay.thread.ThreadPool;
029 import org.mortbay.jetty.Connector;
030 import org.mortbay.jetty.security.UserRealm;
031 import org.mortbay.xml.XmlConfiguration;
032
033 /**
034 * HTTP server implementation.
035 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
036 * @version 0.0.0
037 */
038 public class Server extends org.mortbay.jetty.Server
039 {
040 /**
041 * Component context through which the server configuration uri may be declared.
042 */
043 public interface Context
044 {
045 /**
046 * Get the Jetty XML configuration uri. The configuration uri is
047 * used to establish the default server configuration prior to
048 * customization via the server context. If not supplied the server
049 * will be deployed relative to the supplied context.
050 *
051 * @param uri the default uri
052 * @return a uri referencing a Jetty configuration profile
053 */
054 URI getConfiguration( URI uri );
055
056 /**
057 * Get the assigned thread pool. If no thread pool is
058 * assigned by the deployment scenario a default pool
059 * will be established using the thread pool assigned in the
060 * component internal parts.
061 *
062 * @param pool the default value
063 * @return the resolved thread pool
064 */
065 ThreadPool getThreadPool( ThreadPool pool );
066 }
067
068 /**
069 * Internal parts managemwent interface.
070 */
071 public interface Parts extends PartsManager
072 {
073 /**
074 * Return the default thread pool.
075 * @return the default thread pool.
076 */
077 ThreadPool getThreadPool();
078
079 /**
080 * Return the collection of handlers. For any given request all handlers
081 * in the collection will be supplied with a request irrespective of response
082 * status.
083 *
084 * @return the configured handler collection.
085 */
086 HandlerCollection getHandlers();
087 }
088
089 private final Logger m_logger;
090 private final Context m_context;
091 private final ArrayList m_connections = new ArrayList();
092
093 /**
094 * Creation of a new HTTP server implementation.
095 * @param logger the assigned logging channel
096 * @param context the assigned deployment context
097 * @param parts the parts manager
098 * @exception Exception if an instantiation error occurs
099 */
100 public Server( Logger logger, Context context, Parts parts ) throws Exception
101 {
102 super();
103
104 m_logger = logger;
105 m_context = context;
106
107 getLogger().debug( "commencing http server deployment" );
108 Logger internal = logger.getChildLogger( "jetty" );
109 internal.debug( "assigning internal jetty logger" );
110 LoggerAdapter.setRootLogger( internal );
111
112 Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
113 URI uri = context.getConfiguration( null );
114 if( null != uri )
115 {
116 getLogger().debug( "applying server configuration: " + uri );
117 URL url = uri.toURL();
118 XmlConfiguration config = new XmlConfiguration( url );
119 config.configure( this );
120 }
121
122 //
123 // setup the thread pool
124 //
125
126 ThreadPool pool = context.getThreadPool( null );
127 if( null != pool )
128 {
129 super.setThreadPool( pool );
130 }
131 else
132 {
133 super.setThreadPool( parts.getThreadPool() );
134 }
135
136 //
137 // add connectors, realms and handlers
138 //
139
140 addConnectors( parts );
141 addUserRealms( parts );
142 HandlerCollection collection = parts.getHandlers();
143 setHandler( collection );
144
145 // notify completion of server establishment
146
147 getLogger().debug( "server established" );
148 }
149
150 private void addConnectors( PartsManager parts ) throws Exception
151 {
152 getLogger().debug( "commencing connector addition" );
153 ComponentHandler[] handlers = parts.getComponentHandlers( Connector.class );
154 getLogger().debug( "connector count: " + handlers.length );
155 for( int i=0; i<handlers.length; i++ )
156 {
157 ComponentHandler handler = handlers[i];
158 getLogger().debug( "adding connector: " + handler );
159 try
160 {
161 Provider provider = handler.getProvider();
162 Connector ch = (Connector) provider.getValue( false );
163 m_connections.add( ch );
164 }
165 catch( Throwable e )
166 {
167 final String error =
168 "Failed to deploy content handler: " + handler;
169 throw new Exception( error, e );
170 }
171 }
172 Connector[] connectors = (Connector[]) m_connections.toArray( new Connector[0] );
173 setConnectors( connectors );
174 }
175
176 private void addUserRealms( PartsManager parts ) throws Exception
177 {
178 getLogger().debug( "commencing realm addition" );
179 ArrayList list = new ArrayList();
180 ComponentHandler[] handlers = parts.getComponentHandlers( UserRealm.class );
181 for( int i=0; i<handlers.length; i++ )
182 {
183 ComponentHandler handler = handlers[i];
184 getLogger().debug( "adding realm: " + handler );
185 try
186 {
187 Provider provider = handler.getProvider();
188 org.mortbay.jetty.security.UserRealm ch =
189 (org.mortbay.jetty.security.UserRealm) provider.getValue( false );
190 list.add( ch );
191 }
192 catch( Throwable e )
193 {
194 final String error =
195 "Failed to deploy user realm: " + handler;
196 throw new Exception( error, e );
197 }
198 }
199 UserRealm[] realms = (UserRealm[]) list.toArray( new UserRealm[0] );
200 setUserRealms( realms );
201 }
202
203 private Logger getLogger()
204 {
205 return m_logger;
206 }
207 }